#ifndef MOONLIGHT_OHOS_VIDEOPROCESSOR_H
#define MOONLIGHT_OHOS_VIDEOPROCESSOR_H

class XComponentBackend;
#include "core/gamestream/common/AVBufferPair.h"
#include <Limelight.h>
#include <multimedia/player_framework/native_avcodec_base.h>
#include <mutex>
#include <condition_variable>
#include <list>
#include <thread>

class VideoProcessor {
public:
    explicit VideoProcessor(XComponentBackend *xcomp, OHNativeWindow *nativeWindow);
    virtual ~VideoProcessor();
private:
    VideoProcessor(const VideoProcessor &) = delete;
    VideoProcessor &operator=(const VideoProcessor &) = delete;

public:
    struct LimelightVideoCallbacks {
        static int setup(int videoFormat, int width, int height, int redrawRate, void *context, int drFlags);
        static void start();
        static void stop();
        static void cleanup();
        static int submitDecodeUnit(PDECODE_UNIT decodeUnit);
        static inline const DECODER_RENDERER_CALLBACKS callbacks = {
            .setup = setup,
            .start = start,
            .stop = stop,
            .cleanup = cleanup,
            .submitDecodeUnit = submitDecodeUnit,
        };
    };
    struct VideoDecoderCallbacks {
        static void onError(OH_AVCodec *codec, int32_t errorCode, void *userData);
        static void onStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData);
        static void onNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
        static void onNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
        static inline const OH_AVCodecCallback callbacks = {
            .onError = onError,
            .onStreamChanged = onStreamChanged,
            .onNeedInputBuffer = onNeedInputBuffer,
            .onNewOutputBuffer = onNewOutputBuffer,
        };
    };

private:
    static constexpr bool DEBUG = false;
    friend XComponentBackend;
    XComponentBackend &xcomp;
    OHNativeWindow *const nativeWindow;
    OH_AVCodec *decoder = nullptr;
    struct {
        int videoFormat;
        int width;
        int height;
        int redrawRate;
        void *context;
        int drFlags;
    } limelightParams;
    std::mutex decodeMtx;
    std::condition_variable decodeReadyCond;
    std::list<const AVBufferPair> decodeQueue;
    std::mutex renderMtx;
    std::condition_variable renderReadyCond;
    std::list<const AVBufferPair> renderQueue;
    std::thread renderHandleLoop;

    void handleRender();
};

#define INIT_VIDEO_PROCESSOR_SELF_OR_ELSE(otherwise) \
    ENSURE_GSMGR_OR_ELSE(otherwise); \
    if (GameStreamManager::xcomponentBackend->videoProcessor == nullptr) { \
        OH_LOG_FATAL(LOG_APP, "VideoProcessor is not functional at the time of this %{public}s invocation", __PRETTY_FUNCTION__); \
        otherwise; \
    } \
    auto &self = *GameStreamManager::xcomponentBackend->videoProcessor;

#endif //MOONLIGHT_OHOS_VIDEOPROCESSOR_H
